一、AHT30温湿度传感器
内容在上一级目录。
如果无法预览,请点击 此处下载 AHT30温湿度传感器说明书A0-0417 PDF 文件。
二、ESP-IDF如何编写I2C驱动读取AHT30温湿度数据(简洁版)?
c
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/i2c_master.h" // 引入新版 I2C 主机驱动头文件
// 定义 I2C 引脚和参数
#define I2C_MASTER_SCL_IO 5 // SCL(时钟线)连接的 GPIO 引脚号
#define I2C_MASTER_SDA_IO 6 // SDA(数据线)连接的 GPIO 引脚号
#define AHT30_I2C_ADDR 0x38 // AHT30 传感器的 7 位 I2C 地址(固定为 0x38)
#define I2C_MASTER_FREQ_HZ 100000 // I2C 总线时钟频率:100kHz(标准模式)
static const char *TAG = "AHT30"; // 日志标签,打印日志时会显示 "AHT30"
// AHT30 的初始化命令:0xBE 是命令字,0x08 和 0x00 是参数
// 上电后需要先发送此命令,让传感器进入正常工作状态
static const uint8_t AHT30_CMD_INIT[] = {0xBE, 0x08, 0x00};
// AHT30 的触发测量命令:0xAC 是命令字,0x33 和 0x00 是参数
// 每次想要获取温湿度数据前,都需要先发送此命令触发一次测量
static const uint8_t AHT30_CMD_TRIGGER[] = {0xAC, 0x33, 0x00};
void app_main(void)
{
// =========================================================
// 第一步:配置并初始化 I2C 主机总线
// =========================================================
// i2c_master_bus_config_t 是总线配置结构体,描述这条 I2C 总线的硬件参数
i2c_master_bus_config_t i2c_mst_config = {
.clk_source = I2C_CLK_SRC_DEFAULT, // 使用默认时钟源
.i2c_port = I2C_NUM_0, // 使用 ESP32-S3 的 I2C 端口 0
.scl_io_num = I2C_MASTER_SCL_IO, // 指定 SCL 引脚(GPIO5)
.sda_io_num = I2C_MASTER_SDA_IO, // 指定 SDA 引脚(GPIO6)
.glitch_ignore_cnt = 7, // 毛刺过滤:忽略小于 7 个时钟周期的干扰信号
.flags.enable_internal_pullup = true, // 启用芯片内部上拉电阻(省去外接上拉电阻)
};
i2c_master_bus_handle_t bus_handle; // 总线句柄,后续操作都需要用到它
// i2c_new_master_bus() 根据上面的配置,初始化 I2C 总线,并返回总线句柄
// ESP_ERROR_CHECK() 会检查函数返回值,如果出错则打印错误信息并重启
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
// =========================================================
// 第二步:将 AHT30 设备挂载到 I2C 总线上
// =========================================================
// i2c_device_config_t 是设备配置结构体,描述挂载在总线上的某个从机设备
i2c_device_config_t dev_cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7, // AHT30 使用 7 位地址模式
.device_address = AHT30_I2C_ADDR, // AHT30 的 I2C 地址:0x38
.scl_speed_hz = I2C_MASTER_FREQ_HZ, // 与该设备通信时的 SCL 频率:100kHz
};
i2c_master_dev_handle_t dev_handle; // 设备句柄,后续读写操作都通过它来指定目标设备
// i2c_master_bus_add_device() 将 AHT30 设备注册到总线,返回设备句柄
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
// =========================================================
// 第三步:发送初始化命令,让 AHT30 进入正常工作状态
// =========================================================
// i2c_master_transmit() 向从机发送数据(写操作)
// 参数:设备句柄、要发送的数据指针、数据长度、超时时间(-1 表示永久等待)
ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, AHT30_CMD_INIT, sizeof(AHT30_CMD_INIT), -1));
// 等待 100ms,让 AHT30 完成初始化
vTaskDelay(pdMS_TO_TICKS(100));
// =========================================================
// 主循环:每隔 2 秒读取一次温湿度数据
// =========================================================
while (1) {
// 第四步:发送触发测量命令,通知 AHT30 开始采集温湿度
ESP_ERROR_CHECK(i2c_master_transmit(dev_handle, AHT30_CMD_TRIGGER, sizeof(AHT30_CMD_TRIGGER), -1));
// 第五步:等待 100ms,让 AHT30 完成测量(典型测量时间约 80ms)
vTaskDelay(pdMS_TO_TICKS(100));
// 第六步:从 AHT30 读取 6 字节的原始数据
// AHT30 返回的 6 字节格式:
// data[0]:状态字节
// data[1]~data[2] 高 4 位:湿度原始值(共 20 位)
// data[2] 低 4 位~data[3]:温度/湿度交界
// data[3] 低 4 位~data[5]:温度原始值(共 20 位)
uint8_t data[6] = {0};
// i2c_master_receive() 从从机读取数据(读操作)
// 参数:设备句柄、存放数据的缓冲区、读取字节数、超时时间
ESP_ERROR_CHECK(i2c_master_receive(dev_handle, data, sizeof(data), -1));
// =========================================================
// 第七步:解析原始数据,转换为实际温湿度值
// =========================================================
// 湿度原始值(20位):
// data[1] 的全部 8 位作为高位
// data[2] 的全部 8 位作为中间位
// data[3] 的高 4 位作为低位
// 通过位移和或运算拼接成 20 位整数
uint32_t humidity_raw = ((uint32_t)data[1] << 12) // data[1] 左移 12 位
| ((uint32_t)data[2] << 4) // data[2] 左移 4 位
| (data[3] >> 4); // data[3] 右移 4 位取高 4 位
// 温度原始值(20位):
// data[3] 的低 4 位作为高位
// data[4] 的全部 8 位作为中间位
// data[5] 的全部 8 位作为低位
uint32_t temperature_raw = (((uint32_t)data[3] & 0x0F) << 16) // data[3] 低4位左移16位
| ((uint32_t)data[4] << 8) // data[4] 左移 8 位
| data[5]; // data[5] 直接作为最低位
// 将原始值转换为实际湿度(%RH)
// 公式来自 AHT30 数据手册:湿度 = 原始值 / 2^20 * 100
float humidity = (float)humidity_raw / 1048576.0f * 100.0f;
// 将原始值转换为实际温度(°C)
// 公式来自 AHT30 数据手册:温度 = 原始值 / 2^20 * 200 - 50
float temperature = (float)temperature_raw / 1048576.0f * 200.0f - 50.0f;
// 通过串口打印温湿度结果,%.2f 表示保留两位小数
ESP_LOGI(TAG, "Temperature: %.2f °C, Humidity: %.2f %%", temperature, humidity);
// 等待 2000ms(2秒)后再进行下一次测量
vTaskDelay(pdMS_TO_TICKS(2000));
}
// =========================================================
// 清理资源(注意:while(1) 永远不会退出,所以这里实际不会执行)
// 如果将来改为有限循环,可以用这两行释放资源
// =========================================================
ESP_ERROR_CHECK(i2c_master_bus_rm_device(dev_handle)); // 从总线上移除设备
ESP_ERROR_CHECK(i2c_del_master_bus(bus_handle)); // 删除 I2C 总线
}